#ifndef COMMON_META_OBJECT_H_
#define COMMON_META_OBJECT_H_

#include <fermat/common/singleton.h>
#include <set>


namespace fermat {

template <class B>
class AbstractMetaObject {
public:
	AbstractMetaObject(const char* pName): _name(pName)
	{
	}

	virtual ~AbstractMetaObject()
	{
		for (typename ObjectSet::iterator it = _deleteSet.begin(); it != _deleteSet.end(); ++it)
		{
			delete *it;
		}
	}

	const char* name() const
	{
		return _name;
	}

	virtual B* create() const = 0;
		
	virtual B* instance() const = 0;
	
	virtual bool canCreate() const = 0;
	
	virtual void destroy(B* pObject) const
	{
		typename ObjectSet::iterator it = _deleteSet.find(pObject);
		
		if (it != _deleteSet.end()) {
			_deleteSet.erase(pObject);
			delete pObject;
		}
	}

	B* autoDelete(B* pObject) const
	{
		if (this->canCreate()) {
			_deleteSet.insert(pObject);
		}
		else return NULL;

		return pObject;
	}

	virtual bool isAutoDelete(B* pObject) const
	{
		return _deleteSet.find(pObject) != _deleteSet.end();
	}

private:
	AbstractMetaObject();
	AbstractMetaObject(const AbstractMetaObject&);
	AbstractMetaObject& operator = (const AbstractMetaObject&);

	typedef std::set<B*> ObjectSet;
	
	const char* _name;
	mutable ObjectSet _deleteSet;
};


template <class C, class B>
class MetaObject: public AbstractMetaObject<B> {
public:
	MetaObject(const char* pName): AbstractMetaObject<B>(pName)
	{
	}

	~MetaObject()
	{
	}

	B* create() const
	{
		return new C;
	}
	
	B* instance() const
	{
		assert(false);
		return NULL;
	}
	
	bool canCreate() const
	{
		return true;
	}
};


template <class C, class B> 
class MetaSingleton: public AbstractMetaObject<B>  { 
public: 
	MetaSingleton(const char* pName): AbstractMetaObject<B>(pName)
	{
	}
	
	~MetaSingleton() 
	{
	}
	
	B* create() const
	{
		assert(false);
		return NULL;
	}
	
	bool canCreate() const
	{
		return false;
	}

	B* instance() const
	{
		return _object.instance();
	}

	bool isAutoDelete(B* /*pObject*/) const
	{
		return true;
	}

private: 
	mutable Singleton<C> _object; 
}; 


} 


#endif 